﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace HumanitiesBubbles
{
    public class KeywordHolder : StackPanel
    {
        TextBlock   _keyword = new TextBlock();
        Keywords    _keywords = null;
        Button      _del = null;
        Button      _more = null;
        Point       _mdown = new Point();
        bool        _used = false;
        bool        _locked = false;


        FrameworkElement createMoreButton()
        {
            _more = new Button();
            _more.BorderThickness = new Thickness(0);
            _more.Padding = new Thickness(0);
            _more.Margin = new Thickness(0);
            _more.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Left;
            _more.VerticalContentAlignment = System.Windows.VerticalAlignment.Top;
            _more.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(_more_MouseLeftButtonDown);
            Canvas c = new Canvas();
            Line l1 = new Line();
            l1.X1 = 2;
            l1.X2 = 10;
            l1.Y1 = 6;
            l1.Y2 = 6;
            l1.StrokeThickness = 2;
            l1.Stroke = Brushes.Black;
            c.Children.Add(l1);
            Line l2 = new Line();
            l2.X1 = 6;
            l2.X2 = 6;
            l2.Y1 = 2;
            l2.Y2 = 10;
            l2.StrokeThickness = 2;
            l2.Stroke = Brushes.Black;
            c.Children.Add(l2);
            c.Margin = new Thickness(-1, -1, 0, 0);
            _more.Content = c;
            _more.Width = _more.Height = 14;
            _more.Click += new RoutedEventHandler(_more_Click);
            _more.Opacity = 0.05;
            _more.ToolTip = "Click or Drag to show folder of documents tagged with: " + Keyword;
            return _more;
        }
        FrameworkElement createDelButton()
        {
            _del = new Button();
            Icon_Cancel ic = new Icon_Cancel();
            _del.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Left;
            _del.VerticalContentAlignment = System.Windows.VerticalAlignment.Top;
            _del.Padding = new Thickness(0);
            _del.Margin = new Thickness(0);
            _del.BorderThickness = new Thickness(0);
            _del.Content = ic;
            ic.Margin = new Thickness(-2, -2, 0, 0);
            ic.Width = ic.Height = 14;
            _del.ToolTip = "Remove '" + Keyword + "' keyword from document";
            _del.Width = _del.Height = 14;
            _del.Click += new RoutedEventHandler(_del_Click);
            _del.Opacity = 0.05;
            _del.Visibility = _used ? Visibility.Visible : System.Windows.Visibility.Collapsed;
            return _del;
        }

        void KeywordHolder_MouseEnter(object sender, MouseEventArgs e)
        {
            if (_keywords.Content == _keywords.KeywordsHeader)
                return;
            if (_used)
            _del.Opacity = 1;
            _more.Opacity = 1;
        }
        void KeywordHolder_MouseLeave(object sender, MouseEventArgs e)
        {
            _del.Opacity = 0.05;
            _more.Opacity = 0.05;
        }

        void _more_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            _mdown = e.GetPosition(this);
            Mouse.Capture(_more);
            _more.PreviewMouseMove += new MouseEventHandler(_more_MouseMove);
        }
        void _more_MouseMove(object sender, MouseEventArgs e)
        {
            if (UICommon.Helpers.Distance(_mdown, e.GetPosition(this)) > 4 && _more.IsMouseCaptured)
            {
                e.Handled = true;
                _more.PreviewMouseMove -= new MouseEventHandler(_more_MouseMove);
                DragDrop.DoDragDrop(_more, this, DragDropEffects.Link);
            }
        }
        void _more_Click(object sender, RoutedEventArgs e)
        {
            Mouse.Capture(null);
            _more.PreviewMouseMove -= new MouseEventHandler(_more_MouseMove);
            if (_keywords.Container == null || _keywords.Doq == null)
                return;
            BubbleContainer container = _keywords.Container;
            Point where = container.PointFromScreen(_keywords.PointToScreen(new Point(_keywords.ActualWidth, 0)));
            ViewFiles(Keyword, container, where);
        }
        void _del_Click(object sender, RoutedEventArgs e)
        {
            _keywords.KeywordsList.Children.Remove(this);
            _keywords.KeywordsAvailableList.Children.Add(this);
            _del.Visibility = Visibility.Collapsed;
            _used = false;
        }

        void unused_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {

            if (_keywords.Content != _keywords.KeywordsHeader)
                e.Handled = true;
            this.MouseMove += new MouseEventHandler(UnusedHolder_MouseMove);
            this.MouseUp += new MouseButtonEventHandler(UnusedHolder_MouseUp);
            _mdown = e.GetPosition(this);
            Mouse.Capture(this);
        }
        void UnusedHolder_MouseMove(object sender, MouseEventArgs e)
        {
            if (UICommon.Helpers.Distance(_mdown, e.GetPosition(this)) > 4 && IsMouseCaptured)
            {
                MouseMove -= new MouseEventHandler(UnusedHolder_MouseMove);
                MouseUp -= new MouseButtonEventHandler(UnusedHolder_MouseUp);
                Mouse.Capture(null);
                DragDrop.DoDragDrop(_more, this, DragDropEffects.Link);
                e.Handled = true;
            }
        }
        void UnusedHolder_MouseUp(object sender, MouseButtonEventArgs e)
        {
            MouseMove -= new MouseEventHandler(UnusedHolder_MouseMove);
            MouseUp -= new MouseButtonEventHandler(UnusedHolder_MouseUp);
            Mouse.Capture(null);
            bool found = false;
            foreach (var i in _keywords.KeywordsList.Children)
                if (i is KeywordHolder && (i as KeywordHolder).Keyword == Keyword)
                    found = true;
            _keywords.KeywordsAvailableList.Children.Remove(this);
            if (!found)
                _keywords.KeywordsList.Children.Add(this);
            _del.Visibility = Visibility.Visible;
            _used = true;
            e.Handled = true;
        }
        void keyword_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (_keywords.Content != _keywords.KeywordsHeader)
                e.Handled = true;
            this.MouseMove += new MouseEventHandler(KeywordHolder_MouseMove);
            this.MouseUp += new MouseButtonEventHandler(KeywordHolder_MouseUp);
            _mdown = e.GetPosition(this);
            Mouse.Capture(this);
        }
        void KeywordHolder_MouseUp(object sender, MouseButtonEventArgs e)
        {
            MouseMove -= new MouseEventHandler(KeywordHolder_MouseMove);
            MouseUp -= new MouseButtonEventHandler(KeywordHolder_MouseUp);
            Mouse.Capture(null);
        }
        void KeywordHolder_MouseMove(object sender, MouseEventArgs e)
        {
            if (UICommon.Helpers.Distance(_mdown, e.GetPosition(this)) > 4 && IsMouseCaptured)
            {
                MouseMove -= new MouseEventHandler(KeywordHolder_MouseMove);
                MouseUp   -= new MouseButtonEventHandler(KeywordHolder_MouseUp);
                DragDrop.DoDragDrop(_more, this, DragDropEffects.Link);
                e.Handled = true;
            }
        }

        public KeywordHolder(Keywords keywords, string keyword, bool used, bool locked)
        {
            _locked = locked;
            _used = used;
            _keywords = keywords;
            Margin = new Thickness(8, 0, 0, 0);
            _keyword.FontSize = 11;
            _keyword.Text = keyword;
            Orientation = System.Windows.Controls.Orientation.Horizontal;
            Background = new SolidColorBrush(Color.FromArgb(0x1, 0x1, 0x1, 0x1));
            MouseEnter += new MouseEventHandler(KeywordHolder_MouseEnter);
            MouseLeave += new MouseEventHandler(KeywordHolder_MouseLeave);
            MouseLeftButtonDown += new MouseButtonEventHandler((ss, ee) =>
            {
                if (_used)
                    keyword_MouseLeftButtonDown(ss, ee);
                else unused_MouseLeftButtonDown(ss, ee);
            });
            Children.Add(_keyword);
            Children.Add(createMoreButton());
            if (_locked)
                createDelButton();
            else Children.Add(createDelButton());
        }
        public static void ViewFiles(string keyword, BubbleContainer container,  Point where)
        {
            DoqData dd = null;
            foreach (var doq in DoqDataManager.Doqs)
                if (doq.Type == DoqData.DoqType.Folder)
                    if (doq.Filter == "Keywords:" + keyword)
                    {
                        dd = doq;
                        break;
                    }
            if (dd == null)
            {
                DoqData.SuspendMetadataChangedEvent = true;
                dd = DoqDataManager.Import(Guid.NewGuid(), ".dqg", keyword + " documents", keyword + "documents");
                dd.Filter = "Keywords:" + keyword;
                dd.AddFolder(Guid.Empty);
                dd.AutoSaved = true;
                DoqData.SuspendMetadataChangedEvent = false;
                DoqData.ForceMetadataChangedEvent();
            }
            DoqDataManager.Open(container, dd.Identifier, (Point)where);
        }
        public string      Keyword { get { return _keyword.Text; } }
        public void        SetMinimize(bool state)
        {
            if (state)
                _del.Visibility = _more.Visibility = Visibility.Collapsed;
            else
            {
                _more.Visibility = Visibility.Visible;
                _del.Visibility = _used ? Visibility.Visible : Visibility.Collapsed;
            }
        }

    }
    /// <summary>
    /// Interaction logic for Keywords.xaml
    /// </summary>
    public partial class Keywords : UserControl
    {
        DoqData             _doq       = null;
        BubbleContainer     _container = null;
        Point               _downPt    = new Point();
        MetadataViewer      _metadata  = null;

        void updateAvailables()
        {
            KeywordsAvailableList.Children.Clear();
            foreach (var i in DoqDataKeywordExt.AllKeywords)
            {
                bool found = false;
                foreach (var item in KeywordsList.Children)
                    if ((item is KeywordHolder) && (item as KeywordHolder).Keyword == i)
                    {
                        found = true;
                        break;
                    }
                if (!found)
                    KeywordsAvailableList.Children.Add(new KeywordHolder(this, i, false, false));
            }
        }
        void addNewKeyword()
        {
            string key = KeywordTextBox.Text.Trim();
            foreach (var v in KeywordsList.Children)
                if (v is KeywordHolder && (v as KeywordHolder).Keyword == key)
                    return;
            if (key != "" && key != "<new keyword>")
                KeywordsList.Children.Add(new KeywordHolder(this, key, true, false));
        }

        void saveChanges()
        {
            addNewKeyword();  // add any keyword that has been entered into the keyword text box.
            List<string> doqKeywords = new List<string>();
            List<string> newKeywords = new List<string>();
            List<string> removedKeywords = new List<string>();
            List<string> oldKeywords = _doq == null ? new List<string>() : _doq.Keywords();

            // accumulate all current keywords, and the ones that were just added
            foreach (var data in KeywordsList.Children)
                if (data is KeywordHolder) {
                    doqKeywords.Add((data as KeywordHolder).Keyword);
                    if (_doq == null || !oldKeywords.Contains((data as KeywordHolder).Keyword))
                        newKeywords.Add((data as KeywordHolder).Keyword);
                }

            // accumulate all the keywords that were removed
            foreach (var data in oldKeywords)
                if (!doqKeywords.Contains(data))
                    removedKeywords.Add(data);

            if (_doq == null) {
                if (SaveEvent != null)
                    SaveEvent(newKeywords);
            } else
                saveDoqChanges(_doq, newKeywords, removedKeywords);
            Collapse(true);
        }

        void saveDoqChanges(DoqData doq, List<string> added, List<string> removed)
        {
            DoqData.SuspendMetadataChangedEvent = true;
            foreach (var str in added)
                doq.AddKeyword(str);
            foreach (var str in removed)
                doq.RemKeyword(str);
            DoqData.SuspendMetadataChangedEvent = false;
            DoqData.SendMetadataChangedEvent(doq);
        }

        public event EventHandler KeywordsDragEvent;

        void mouseMove(object sender, MouseEventArgs e)
        {
            if (UICommon.Helpers.Distance(e.GetPosition(_container), _downPt) > 4)
            {
                PreviewMouseMove -= new MouseEventHandler(mouseMove);
                if (KeywordsDragEvent != null)
                    KeywordsDragEvent(this, null);
            }
        }

        event EventHandler Collapsed; 

        public delegate void SaveHandler(List<string> keywords);
        public event SaveHandler SaveEvent;
        public Keywords()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(Keywords_Loaded);
        }
        /// <summary>
        /// A control for display and editing the keywords associated with a document.
        /// </summary>
        /// <param name="container"></param>
        /// <param name="doq"></param>
        public Keywords(BubbleContainer container, DoqData doq):this()
        {
            _container = container;
            _doq = doq;
        }

        public void Multiselect(BubbleContainer container)
        {
            _container = container;
            Keywords_Loaded(null, null);
        }

        void Keywords_Loaded(object sender, RoutedEventArgs e)
        {
            Collapse(true);

            MouseWheel += new MouseWheelEventHandler((ss, ee) => ee.Handled = true);
            KeywordsList.MouseLeftButtonDown += new MouseButtonEventHandler((ss, ee) => ee.Handled = Content != KeywordsHeader);
            KeywordsList.MouseLeftButtonUp += new MouseButtonEventHandler((ss, ee) => ee.Handled = Content != KeywordsHeader);
            KeywordsAvailableList.MouseLeftButtonDown += new MouseButtonEventHandler((ss,ee) => ee.Handled = true);
            KeywordsAvailableList.MouseLeftButtonUp += new MouseButtonEventHandler((ss,ee) => ee.Handled = true);
            MouseLeftButtonDown += new MouseButtonEventHandler((ss, ee) =>
            {
                ee.Handled = true;
                _downPt = ee.GetPosition(_container);
                PreviewMouseMove += new MouseEventHandler(mouseMove);
                MouseLeftButtonUp += new MouseButtonEventHandler(Keywords_MouseLeftButtonUp);
                Mouse.Capture(this);
            });
            KeywordTextBox.GotFocus += new RoutedEventHandler((ss, ee) => KeywordTextBox.Text = "");
            KeywordTextBox.KeyUp += new KeyEventHandler(KeywordTextBox_KeyUp);
            //MouseLeave += new MouseEventHandler((ss, ee) => MinWidth = 0);
            cancelButton.Click += new RoutedEventHandler((ss, ee) =>
            {
                MetadataHeader.Content = null;
                _metadata = null;
                Collapse(true);
            });
            okButton.Click += new RoutedEventHandler((ss, ee) => saveChanges() );
            KeywordsAvailableGroup.MouseLeftButtonDown += new MouseButtonEventHandler((ss, ee) =>
            {
                ee.Handled = true;
                Mouse.Capture(KeywordsAvailableGroup);
            });
            KeywordsAvailableGroup.MouseLeftButtonUp += new MouseButtonEventHandler((ss, ee) =>
            {
                ee.Handled = true;
                Mouse.Capture(null);
                if (KeywordsAvailableGroup.MaxHeight == 30)
                    KeywordsAvailableGroup.MaxHeight = 100;
                else KeywordsAvailableGroup.MaxHeight = 30;
            });
            Metadata.MouseLeftButtonDown += new MouseButtonEventHandler((ss, ee) =>
            {
                ee.Handled = true;
                Mouse.Capture(Metadata);
            });
           
            Metadata.MouseLeftButtonUp += new MouseButtonEventHandler((ss, ee) =>
            {
                ee.Handled = true;
                Mouse.Capture(null);
                if (MetadataHeader.Content == null)
                {
                    _metadata = _doq == null ? new MetadataViewer() : new MetadataViewer(_doq.Metadata, _doq.CreatorID, true, _doq.URL);
                    _metadata.FontSize = 10;
                    _metadata.MouseLeftButtonDown += new MouseButtonEventHandler((sss, eee) => eee.Handled = true);
                    MetadataHeader.Content = _metadata;
                    new BubbleMetadataTag(Guid.Empty, "", _doq).UseViewer(_metadata);
                }
                else
                {
                    if (_metadata.Visibility == Visibility.Collapsed)
                    {
                        _metadata.Visibility = Visibility.Visible;
                        _metadata.UpdateAll(_doq.Metadata, _doq.URL);
                        KeywordPanel.MaxWidth = Math.Max(MaxWidth,250);
                    }
                    else
                    {
                        KeywordPanel.MaxWidth = double.PositiveInfinity;
                        _metadata.Visibility = Visibility.Collapsed;
                    }
                }
            });
        }

        void KeywordTextBox_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Tab)
            {
                foreach (var item in KeywordsAvailableList.Children)
                    if (item is KeywordHolder && (item as KeywordHolder).Visibility == Visibility.Visible)
                    {
                        KeywordTextBox.Text = (item as KeywordHolder).Keyword;
                        KeywordTextBox.SelectionStart = KeywordTextBox.Text.Length;
                        break;
                    }
            } else
            if (e.Key == Key.Return)
            {
                addNewKeyword();
                KeywordTextBox.Text = "";
                foreach (var item in KeywordsAvailableList.Children)
                    if (item is KeywordHolder)
                    {
                        (item as KeywordHolder).Visibility = Visibility.Visible;
                        (item as KeywordHolder).Background = Brushes.Transparent;
                        KeywordsAvailableList.Children.Remove(item as KeywordHolder);
                        break; 
                    }
            }
            else
            {
                bool first = true;
                var available = DoqDataKeywordExt.AllKeywords;
                var items = new UIElement[KeywordsAvailableList.Children.Count];
                KeywordsAvailableList.Children.CopyTo(items, 0);
                foreach (var item in items)
                    if (item is KeywordHolder)
                    {
                        (item as KeywordHolder).Visibility = Visibility.Collapsed;
                        var suggestion = (item as KeywordHolder).Keyword;
                        string lowercaseKeywords = suggestion.ToLower();
                        string lowercaseSearch = KeywordTextBox.Text.ToLower();
                        if (lowercaseKeywords.Contains(lowercaseSearch))
                        {
                            if (first)
                            {
                                first = false;
                                (item as KeywordHolder).Background = Brushes.Yellow;
                            }
                            else (item as KeywordHolder).Background = Brushes.Transparent;
                            (item as KeywordHolder).Visibility = Visibility.Visible;
                            if (lowercaseKeywords.StartsWith(lowercaseSearch))
                            {
                                KeywordsAvailableList.Children.Remove(item as KeywordHolder);
                                KeywordsAvailableList.Children.Insert(0, (item as KeywordHolder));
                            }
                        }
                    }
            }
            e.Handled = true;
        }

        void Keywords_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            PreviewMouseMove -= new MouseEventHandler(mouseMove);
            if (Content == KeywordsHeader)
                Expand();
            else Collapse(true);
            e.Handled = true;
            MouseLeftButtonUp -= new MouseButtonEventHandler(Keywords_MouseLeftButtonUp);
            Mouse.Capture(null);
          
        }

        /// <summary>
        /// The Document for which this control is displaying ckeywords
        /// </summary>
        public DoqData         Doq                 { get { return _doq; } set { _doq = value; } }
        /// <summary>
        /// Container that this keywords belongs to
        /// </summary>
        public BubbleContainer Container           { get { return _container; } set { _container = value; }}
        /// <summary>
        /// Whether the keyword box is expanded for editing
        /// </summary>
        public bool            IsCollapsed         { get { return Content != KeywordDialog; } }
        /// <summary>
        /// Updates the visual display of the list of Keywords applied to a document 
        /// </summary>
        public void Update()
        {
            if (_doq == null)
                return;
            List<string> locked = _doq.LockedKeywords();
            List<string> editable = _doq.EditableKeywords();
            KeywordsList.Children.Clear();
            foreach (var key in locked)
                KeywordsList.Children.Add(new KeywordHolder(this, key, true, true));
            foreach (var key in editable)
                KeywordsList.Children.Add(new KeywordHolder(this, key, true, false));
            foreach (var k in KeywordsList.Children)
                if (k is KeywordHolder)
                    (k as KeywordHolder).SetMinimize(Content != KeywordDialog);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="on"></param>
        public void SetHighlight(bool on)
        {
            KeywordsList.Background = on ? Brushes.Beige : Brushes.Transparent;
            if (!on)
                Collapse(false);
        }
        /// <summary>
        /// Collapses the keywords selection control into a title, rotated by 90 degrees
        /// </summary>
        public void Collapse(bool force)
        {
            if (!force && ((ContextMenu != null && ContextMenu.IsOpen)|| (Content != KeywordsHeader)))
                return;
            MinWidth = 0;
            KeywordPanel.Children.Remove(KeywordsHeader);
            this.Content = KeywordsHeader;
            KeywordsHeader.BorderThickness = new Thickness(1, 1, 1, 1);
            KeywordsHeader.Background = new SolidColorBrush(Color.FromArgb(0x1, 0x1, 0x1, 0x1));
            KeywordTextBox.Text = "<new keyword>";
            if (_metadata != null)
            {
                _metadata.Flush();
                _metadata.Visibility = Visibility.Collapsed;
            }
            Update();
            if (Collapsed != null)
                Collapsed(this, null);
          
        }
        /// <summary>
        /// Expands the rotated keyword title into a control containing available and assigned keywords.
        /// </summary>
        public void Expand()
        {
            Content = KeywordDialog;
            KeywordPanel.MaxWidth = double.PositiveInfinity;
            if (KeywordsHeader.Parent != KeywordPanel)
                KeywordPanel.Children.Insert(0,KeywordsHeader);
            Update();
            updateAvailables();
            if (_container != null && _doq != null && _container.FindUnminimizedBubbleByContentID(_doq.Identifier) != null)
                UICommon.Helpers.BringToFront(_container.FindUnminimizedBubbleByContentID(_doq.Identifier));
            MinWidth = Math.Max(150,ActualWidth);
            KeywordTextBox.Focus();
            FocusManager.SetWpfFocus(KeywordTextBox);
         
        }

        /// <summary>
        /// Creates a Window that contains the keyword selection control
        /// </summary>
        /// <param name="container"></param>
        /// <param name="doq"></param>
        /// <returns></returns>
        public static Window KeywordsWindow(BubbleContainer container, DoqData doq)
        {
            Window w = new Window();
            w.WindowStartupLocation = WindowStartupLocation.Manual;
            w.Left = System.Windows.Forms.Cursor.Position.X;
            w.Top = System.Windows.Forms.Cursor.Position.Y;
            var key = new Keywords(container, doq);
            key.Expand();
            //key.Collapsed += new EventHandler((ss,ee) => w.Close()); 
            w.Content = key;
            w.Topmost = true;
            w.Title = "Keywords";
            w.SizeToContent = SizeToContent.WidthAndHeight;
            w.ResizeMode = ResizeMode.NoResize;
            return w;
        }
    }
}
